import sys
import avahi
import dbus
from avahi_browse import AvahiDiscover
from SignalDispatcher import SignalDispatcher

__all__ = ["ZeroconfService"]

class ServiceConnector(SignalDispatcher):
    def __init__(self, SystemData):
        SignalDispatcher.__init__(self)
        self.system = SystemData
        servname_base = self.system.appname + '-' + self.system.name
        self.hosts = {}
        self.services = {}
        self.initSignals()
        servinfo = []        
        #servinfo.append(ServiceInfo('xmlrpc', ZeroconfPublisher, name=servname_base, port=8000, stype="_xmlrpc._tcp", text=self.system.id))
        if 'daemon' in sys.argv:
            servinfo.append(ServiceInfo('jsonrpc-backend', ZeroconfPublisher, name=servname_base,
                                         port=7081, stype="_jsonrpc_backend._tcp", text=self.system.id))
        else:
            servinfo.append(ServiceInfo('jsonrpc', ZeroconfPublisher, name=servname_base,
                                         port=7080, stype="_jsonrpc._tcp", text=self.system.id))
        for serv in servinfo:
            self.services.update({serv.name:serv.classObj(**serv._kwargs)})
        self.publish()
        self.listeners = {}
        #self.listeners.update({'xmlrpc':AvahiDiscover('_xmlrpc._tcp')})
        self.listeners.update({'jsonrpc':AvahiDiscover('_jsonrpc._tcp')})
        for key, val in self.listeners.iteritems():
            val.connect('new_host', self.new_host)
            val.connect('remove_host', self.remove_host)
    def initSignals(self):
        self.register_signal('new_host')
        self.register_signal('remove_host')
        self.register_signal('host_connection')
        self.register_signal('got_local_address')
    def publish(self, servicename=None):
        if servicename is None:
            for service in self.services.itervalues():
                service.publish()
        elif servicename in self.services:
            self.services[servicename].publish()
    def unpublish(self, servicename=None):
        if servicename is None:
            for service in self.services.itervalues():
                service.unpublish()
        elif servicename in self.services:
            self.services[servicename].unpublish()
    def new_host(self, **kwargs):
        data = kwargs.get('data')
        if data['id'] != self.system.id:
            self.hosts.update({data['id']:Host(data)})
            self.emit('new_host')
        elif self.system.address is None:
            self.system.address = data['address']
            self.emit('got_local_address', address=data['address'])
    def remove_host(self, **kwargs):
        data = kwargs.get('data')
        hostid = None
        for key, val in self.hosts.iteritems():
            if val.name == data['name'] and val.stype == data['stype']:
                hostid = key
        if hostid is not None and hostid in self.hosts:
            del self.hosts['hostid']
            self.emit('remove_host', id=hostid)
    def set_host_connected(self, id, state):
        if id in self.hosts:
            self.hosts[id].connected = state
            self.emit('host_connection', id=id, state=state)

class Host(object):
    def __init__(self, hostdata, connected=False):
        for key, val in hostdata.iteritems():
            setattr(self, key, val)
        self.hostdata = hostdata
        self.connected = connected
        

class ServiceInfo(object):
    def __init__(self, servname, classObj, **kwargs):
        self.name = servname
        self.classObj = classObj
        self._kwargs = kwargs
        if 'name' in kwargs:
            self._kwargs.update({'name':kwargs.get('name') + '-' + self.name})

class ZeroconfPublisher:
    def __init__(self, **kwargs):
        kwargs.setdefault('stype', '_http._tcp')
        kwargs.setdefault('domain', '')
        kwargs.setdefault('host', '')
        kwargs.setdefault('text', '')
        self.name = kwargs.get('name')
        self.stype = kwargs.get('stype')
        self.domain = kwargs.get('domain')
        self.host = kwargs.get('host')
        self.port = kwargs.get('port')
        self.text = kwargs.get('text')
    def publish(self):
        #print 'text=' + self.text
        txt = avahi.string_array_to_txt_array(self.text)
        #print txt
        bus = dbus.SystemBus()
        server = dbus.Interface(
                         bus.get_object(
                                 avahi.DBUS_NAME,
                                 avahi.DBUS_PATH_SERVER),
                        avahi.DBUS_INTERFACE_SERVER)

        g = dbus.Interface(
                    bus.get_object(avahi.DBUS_NAME,
                                   server.EntryGroupNew()),
                    avahi.DBUS_INTERFACE_ENTRY_GROUP)

        g.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC,dbus.UInt32(0),
                     self.name, self.stype, self.domain, self.host,
                     dbus.UInt16(self.port), txt)

        g.Commit()
        self.group = g
    def unpublish(self):
        self.group.Reset()

if __name__ == '__main__':
    from SystemData import SystemData
    import gtk
    sysdata = SystemData()
    servconnector = ServiceConnector(sysdata)
    gtk.main()
